#include "Object.h"
//#include <iostream>

void PlaneObject::resize()
{
	int i;
	maxShapes+=32;
	Plane * temp;
	temp = (Plane *) malloc (maxShapes*sizeof(Plane));
	for (i = 0; i < currentShapes; i++)
	{
		temp[i] = planeList[i];
	}
	delete [] planeList;
	planeList = temp;
}

void SphereObject::resize()
{
	int i;
	maxShapes+=32;
	Sphere * temp;
	temp = (Sphere *) malloc (maxShapes*sizeof(Sphere));
	for (i = 0; i < currentShapes; i++)
	{
		temp[i] = sphereList[i];
	}
	delete [] sphereList;
	sphereList = temp;
}

void PlaneObject::addPlane(Point3 center, Point3 vec1, Point3 vec2, double width, double length)
{
	if (currentShapes == maxShapes)
		resize();
	Plane newPlane(vec1, width, vec2, length, center);
	planeList[currentShapes] = newPlane;
	currentShapes++;
}


void PlaneObject::addPlane(Plane p)
{
	if (currentShapes == maxShapes)
		resize();
	planeList[currentShapes] = p;
	currentShapes++;
}

void SphereObject::addSphere(Point3 center, double radius)
{
	if (currentShapes == maxShapes)
		resize();
	Sphere newSphere(center, radius);
	sphereList[currentShapes] = newSphere;
	currentShapes++;
}

void PlaneObject::Test(){};

void PlaneObject::getIntercept(Point3 startPoint,
                      Point3 direction,
                      double * interceptTime,
                      Point3 * interceptPoint,
                      Point3 * interceptNormal)
{
	int i = 1;
	//normalize(&direction);
	double tempTime;
	Point3 tempPoint;
	Point3 tempNormal;
	planeList[0].getIntercept(startPoint, direction, interceptTime, interceptPoint, interceptNormal);
    while (i < currentShapes)
	{
		planeList[i].getIntercept(startPoint, direction, &tempTime, &tempPoint, &tempNormal);
		if ( tempTime >= 0 && (tempTime < *interceptTime || *interceptTime < 0) )
		{
			*interceptTime = tempTime;
			*interceptPoint = tempPoint;
			*interceptNormal = tempNormal;
		}
		i++;
	}
}

void SphereObject::getIntercept(Point3 startPoint,
                      Point3 direction,
                      double * interceptTime,
                      Point3 * interceptPoint,
                      Point3 * interceptNormal)
{
	int i = 1;
	double tempTime;
	Point3 tempPoint;
	Point3 tempNormal;
	sphereList[0].getIntercept(startPoint, direction, interceptTime, interceptPoint, interceptNormal);
	while (i < currentShapes)
	{
		sphereList[i].getIntercept(startPoint, direction, &tempTime, &tempPoint, &tempNormal);
		if (tempTime < *interceptTime)
		{
			*interceptTime = tempTime;
			*interceptPoint = tempPoint;
			*interceptNormal = tempNormal;
		}
		i++;
	}
}


PlaneObject * createSquare(Point3 center, double width, double height, 
	double depth, Color4 color, double reflectance)
{
    //std::cout << color.red << " " << color.green << " " << color.blue << std::endl;
	PlaneObject* p = new PlaneObject(); //(PlaneObject*) malloc( sizeof(PlaneObject) );
	p->setColor(color);
	p->setReflectance(reflectance);

	Point3 xVector(1, 0, 0);
	Point3 yVector(0, 1, 0);
	Point3 zVector(0, 0, 1);
	normalize(&xVector);
	normalize(&yVector);
	normalize(&zVector);

	Point3 top(center.x, center.y+height/2, center.z);
	Point3 bottom(center.x, center.y-height/2, center.z);
	Point3 front(center.x, center.y, center.z+depth/2);
	Point3 back(center.x, center.y, center.z-depth/2);
	Point3 right(center.x+width/2, center.y, center.z);
	Point3 left(center.x-width/2, center.y, center.z);

	Plane topPlane(xVector, width, zVector, depth, top);
	Plane bottomPlane(xVector, width, zVector, depth, bottom);
	Plane leftPlane(zVector, depth, yVector, height, left);
	Plane rightPlane(zVector, depth, yVector, height, right);
	Plane frontPlane(xVector, width, yVector, height, front);
	Plane backPlane(xVector, width, yVector, height, back);

	p->addPlane(topPlane);
	p->addPlane(bottomPlane);
	p->addPlane(leftPlane);
	p->addPlane(rightPlane);
	p->addPlane(frontPlane);
	p->addPlane(backPlane);

	return p;
}

PlaneObject * createSquare(Point3 center, double width, double height, 
	double depth, Color4 color, double reflectance, double xRot, 
	double yRot, double zRot)
{
	int i;
	PlaneObject * p =  new PlaneObject(); 
	p->setColor(color);
	p->setReflectance(reflectance);
	float rotationResult16[16];
	Point3 endVector;
	glPushMatrix();
	glLoadIdentity();
	glRotatef(zRot, 0, 0, 1);
	glRotatef(yRot, 0, 1, 0);
	glRotatef(xRot, 1, 0, 0);
	glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)&rotationResult16);
	glPopMatrix();
	
	Point3 xVector(1, 0, 0);
	Point3 yVector(0, 1, 0);
	Point3 zVector(0, 0, 1);
	xVector = rotateVector(xVector, rotationResult16);
	yVector = rotateVector(yVector, rotationResult16);
	zVector = rotateVector(zVector, rotationResult16);
	normalize(&xVector);
	normalize(&yVector);
	normalize(&zVector);
	
	Point3 top(center.x, center.y+height/2, center.z);
	Point3 bottom(center.x, center.y-height/2, center.z);
	Point3 front(center.x, center.y, center.z+depth/2);
	Point3 back(center.x, center.y, center.z-depth/2);
	Point3 right(center.x+width/2, center.y, center.z);
	Point3 left(center.x-width/2, center.y, center.z);

	top = rotateVector(top, rotationResult16);
	bottom = rotateVector(bottom, rotationResult16);
	front = rotateVector(front, rotationResult16);
	back = rotateVector(back, rotationResult16);
	right = rotateVector(right, rotationResult16);
	left = rotateVector(left, rotationResult16);
	
	Plane topPlane(xVector, width, zVector, depth, top);
	Plane bottomPlane(xVector, width, zVector, depth, bottom);
	Plane leftPlane(zVector, depth, yVector, height, left);
	Plane rightPlane(zVector, depth, yVector, height, right);
	Plane frontPlane(xVector, width, yVector, height, front);
	Plane backPlane(xVector, width, yVector, height, back);
	
	p->addPlane(topPlane);
	p->addPlane(bottomPlane);
	p->addPlane(leftPlane);
	p->addPlane(rightPlane);
	p->addPlane(frontPlane);
	p->addPlane(backPlane);

	return p;
}

Point3 rotateVector(Point3 vec, float rotMatrix[16])
{
	float result[16];
	float vecA[3];
	vecA[0] = vec.x;
	vecA[1] = vec.y;
	vecA[2] = vec.z;
	glPushMatrix();
	glLoadIdentity();
	glMultMatrixf(rotMatrix);
	glMultMatrixf(vecA);
	glGetFloatv(GL_MODELVIEW_MATRIX, result);
	//0-2 has the rotated vector
	glPopMatrix();

	vec.x = result[0];
	vec.y = result[1];
	vec.z = result[2];

	return vec;
}

SphereObject * createSphere(Point3 center, double radius, Color4 color, double reflectance)
{
	SphereObject *s = new SphereObject();
	s->setColor(color);
	s->setReflectance(reflectance);
	s->addSphere(center, radius);
	return s;
}